package com.icss.ah.base.filter;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.StringTokenizer;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.log4j.Logger;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import com.icss.ah.base.service.FilterLogService;
import com.icss.ah.base.util.DateUtils;
import com.icss.ah.base.util.IcssUtil;
import com.icss.ah.base.util.ResourceLoader;
import com.icss.ah.login.bean.UserInfoBean;
import com.icss.ah.login.service.LoginService;
import com.icss.j2ee.util.UUID;

/**
 * 用于检测用户是否登陆的过滤器，如果未登录，则重定向到指的登录页面 配置参数 checkSessionKey 需检查的在 Session 中保存的关键字
 * redirectURL 如果用户未登录，则重定向到指定的页面，URL不包括 ContextPath notCheckURLList
 * 不做检查的URL列表，以分号分开，并且 URL 中不包括 ContextPath
 * @author csadchen
 * @date 2016-09-28
 */
public class SessionFilter implements Filter {
	protected FilterLogService filterLogService;
	protected LoginService loginService;
	
	private final Logger errlog = Logger.getLogger("E");
	private final Logger infolog = Logger.getLogger("I");
	
	protected FilterConfig filterConfig = null;
	//页面重定向地址
	private String redirectMainURL = null;
	//对应微信公众号信息
	private String corpId = null;
	//不需过滤的访问地址集
	private List notCheckURLList = new ArrayList();
	/**
	 * 初始化
	 */
	public void init(FilterConfig filterConfig) {
		try{
			this.filterConfig = filterConfig;
			ServletContext servletContext = filterConfig.getServletContext();
			WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
			this.filterLogService = (FilterLogService) wac.getBean("filterLogService");
			this.loginService = (LoginService) wac.getBean("loginService");
			
			redirectMainURL = "/noLogin.jsp?flag=noSession";
			String notCheckURLListStr = "/login;/login.do;/expressBird;login_out.do;index.jsp;error.jsp;/verifyCode";
			if (notCheckURLListStr != null) {
				StringTokenizer st = new StringTokenizer(notCheckURLListStr, ";");
				notCheckURLList.clear();
				while (st.hasMoreTokens()) {
					notCheckURLList.add(st.nextToken());
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
			errlog.error("SessionFilter|init", e);
		}
	}
	public void doFilter(ServletRequest servletRequest,
		ServletResponse servletResponse, FilterChain filterChain){
		try{
			HttpServletRequest request = (HttpServletRequest) servletRequest;
			HttpServletResponse response = (HttpServletResponse) servletResponse;
			
			HttpSession session = request.getSession(true);//TODO
			String reqUrl = request.getRequestURI();
			//判断访问路径是否需要经过过滤验证
			if(this.noNeedCheck(reqUrl)){
				//无需验证
				filterChain.doFilter(servletRequest, servletResponse);
			} else {
				//如果session超时，系统跳转到登录界面
				infolog.info("SessionFilter|session:"+session);
				if(session!=null){
					//从session中取账号
					String userCode = (String)session.getAttribute("userCode");
					userCode = userCode == null || userCode.equalsIgnoreCase("null") ? "" : userCode;
					infolog.info("SessionFilter|userCode:"+userCode);
					session.setAttribute("userCode",userCode);
					//判断账号是否存在，存在则正常访问，不存在则提示session过期，重新登录
					if(userCode==null || "".equals(userCode)||"null".equalsIgnoreCase(userCode)){
						//session过期，重新登录
						response.sendRedirect(request.getContextPath() + redirectMainURL);
					} else {
						/**
						 * 判断店铺是否注册，已注册则记录操作日志
						 */
						saveOpeLog(request, userCode);
						//session没过期，正常访问
						filterChain.doFilter(servletRequest, servletResponse);
					}
				} else {
					response.sendRedirect(request.getContextPath() + redirectMainURL);
				}
			}
		}catch(Exception ex){
			ex.printStackTrace();
			errlog.error("SessionFilter|doFilter", ex);
		}
	}
	/**
	 * 记录店铺操作记录
	 * @param request
	 * @param shopId
	 */
	public void saveOpeLog(HttpServletRequest request,String userCode){
		try{
			//根据账号获取基本信息
			UserInfoBean userInfo = loginService.getUserInfo(userCode);
			//获取用户店铺id
			String shopId = userInfo.getShopId();
			shopId = shopId == null ? "" : shopId;
			infolog.info("SessionFilter|saveOpeLog|shopId:"+shopId);
			if(!shopId.equals("")){
				//已注册店铺，记录操作记录
				//获取访问链接地址
				String requestURL = request.getRequestURL().toString();//
				String requestURI = request.getRequestURI();
				//获取访问对应方法
				String menuMethod = request.getParameter("method");
				menuMethod = menuMethod == null ? "" : menuMethod;
				//访问用户的IP
				String userIp = getIpAddress(request);
				//服务器的IP
				String serverIp = requestURL.replace("http://", "").substring(0, requestURL.replace("http://", "").indexOf("/"));
				//访问的参数组合
				StringBuffer sb = new StringBuffer();
				try{
					Enumeration emum = request.getParameterNames();
					while(emum.hasMoreElements()){
						String name=(String)emum.nextElement();
						String value=request.getParameter(name);
						if (!"method".equals(name)) {
							sb.append("&" + name + "=" + value);
						}
					}
				} catch(Exception e){
					e.printStackTrace();
					errlog.error("SessionFilter|saveOpeLog|emum", e);
				}
				//装载日志记录参数
				HashMap hm = new HashMap();
				hm.put("opeUuid", new UUID().toString());
				hm.put("corpId", userInfo.getCorpId());
				hm.put("shopId", shopId);
				hm.put("visitMonth", DateUtils.getCurDateString("yyyyMM"));
				hm.put("visitDate", DateUtils.getCurDateString("yyyy-MM-dd"));
				hm.put("visitTime", DateUtils.getCurDateString("yyyy-MM-dd HH:mm:ss"));
				hm.put("menuUrl", requestURI);
				hm.put("menuMethod", menuMethod);
				String menuParam = sb.toString();
				if(menuParam.getBytes("utf-8").length>600){
					menuParam = IcssUtil.bSubstring(menuParam, 600) ;
				}
				hm.put("menuParam", sb.toString());
				hm.put("userIp", userIp);
				hm.put("serverIp", serverIp);
				//记录访问日志
				infolog.info("SessionFilter|saveOpeLog|hm:"+hm);
				filterLogService.saveOpeLog(hm);
			}
		} catch (Exception e) {
			e.printStackTrace();
			errlog.error("SessionFilter|saveOpeLog", e);
		}
	}
	/**
	 * 判断uri是否在白名单里面
	 * @param uri
	 * @return
	 */
	private boolean noNeedCheck(String uri) {
		if (uri.equals("/b2cShop/") || uri.equals("/") || uri.equals("")) {
			return true;
		}

		for (int i = 0; i < notCheckURLList.size(); i++) {
			String noCheck = (String) notCheckURLList.get(i);
			if (uri.indexOf(noCheck)>-1) {
				return true;
			}
		}

		return false;
	}
	/*
	 * 获取访问IP
	 */
	public String getIpAddress(HttpServletRequest request) {
		String ip = request.getHeader("x-forwarded-for");
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("WL-Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("HTTP_CLIENT_IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("HTTP_X_FORWARDED_FOR");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getRemoteAddr();
		}
		ip = ip == null ? "" : ip;
		return ip;
	}
	public void destroy() {
		notCheckURLList.clear();
	}
}
